package com.jh.loadbalance.server.controller;

import com.jh.loadbalance.server.mvc.annotation.SemaphoreCircuitBreaker;
import com.jh.loadbalance.server.mvc.annotation.TimeoutCircuitBreaker;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Random;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

@RestController
public class SeverController {

    private Random random = new Random();
    @HystrixCommand(
            fallbackMethod = "errorContent",
            commandProperties = {
                    @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "100")
            }
    )
    @RequestMapping("/message/{message}")
    public String message(@PathVariable String message) throws InterruptedException {

        int sleepTime = random.nextInt(200);
        System.out.println("Sleep Cost：" + sleepTime + " ms");
        Thread.sleep(sleepTime);

        System.out.println("Hello：" + message);
        return "Hello：" + message;
    }
    public String errorContent(String message) {
        return "Fail Request";
    }

    private String sleepMessage(String message) throws InterruptedException {
        int sleepTime = random.nextInt(200);
        System.out.println("Sleep Cost：" + sleepTime + " ms");
        Thread.sleep(sleepTime);
        System.out.println("Hello：" + message);
        return "Hello：" + message;
    }

    private ExecutorService executorService = Executors.newSingleThreadExecutor();
    @RequestMapping("/message2/{message}")
    public String message2(@PathVariable String message) {
        Future<String> future = executorService.submit(() -> this.sleepMessage(message));
        String returnVal = null;
        try {
            returnVal = future.get(100, TimeUnit.MILLISECONDS);
        } catch (InterruptedException | ExecutionException | TimeoutException e) {
            returnVal = "Fault";
        }
        return returnVal;
    }

    @RequestMapping("/middle/message/{message}")
    public String middleMessage(@PathVariable String message) throws Exception {
        Future<String> future = executorService.submit(() -> this.sleepMessage(message));
        String returnVal = null;
        try {
            returnVal = future.get(100, TimeUnit.MILLISECONDS);
        } catch (TimeoutException e) {
            future.cancel(true); // 超过100ms就熔断它，不返回
            throw e;
        }
        return returnVal;
    }

    @RequestMapping("/advince/message/{message}")
    public String advinceMessage(@PathVariable String message) throws InterruptedException {
        return this.sleepMessage(message);
    }

    @TimeoutCircuitBreaker(timeout = 100)
    @RequestMapping("/annotation/timeout/message/{message}")
    public String annotationTimeoutMessage(@PathVariable String message) throws InterruptedException {
        return this.sleepMessage(message);
    }

    @SemaphoreCircuitBreaker(1)
    @RequestMapping("/annotation/semaphore/message/{message}")
    public String annotationSemaphoreMessage(@PathVariable String message) throws InterruptedException {
        return this.sleepMessage(message);
    }
}
